package ar.edu.caece.compiler.grammar.attributes.tree;

import ar.edu.caece.compiler.grammar.attributes.DeclaracionVariable;

public class NodeAsignacion extends NodeSentencia {
	private DeclaracionVariable variable;
	private NodeExpr expresion;
	private NodeExpr posArray;
	
	public NodeAsignacion(DeclaracionVariable variable, NodeExpr expresion) {
		super();
		this.setVariable(variable);
		this.expresion = expresion;
	}

	public NodeExpr getExpresion() {
		return expresion;
	}
	public void setExpresion(NodeExpr expresion) {
		this.expresion = expresion;
	}

	public void setPosArray(NodeExpr posArray) {
		this.posArray = posArray;
	}

	public NodeExpr getPosArray() {
		return posArray;
	}
	
	public String toString() {
		return "[Nodo Asignacion -> Variable: " + variable + " expresion " + expresion + "posarray: " + posArray +"]"; 
	}
	
	@Override
	public void propagarEntornoSuperior(NodeFuncProc nodeFuncProc) {
		entornoSuperior = nodeFuncProc;
		expresion.propagarEntornoSuperior(nodeFuncProc);
		if(posArray!=null) posArray.propagarEntornoSuperior(nodeFuncProc);
	}
	
	@Override
	public void propagateRoot(NodeListaBloques raiz) {
		expresion.propagateRoot(raiz);
	}
	
	private int posVariable(DeclaracionVariable declaracion) {
		int pos=10;
		if(declaracion.isParametro()) {
				pos+=2*entornoSuperior.cantidadVariablesLocales()+8;
				pos+=declaracion.getOrdenVariable()*2;

		} else {
			pos+=(1+declaracion.getOrdenVariable())*2;
		}
		return pos;
	}
	
	@Override
	public String generateCode() {
		StringBuilder codeGen = new StringBuilder();
		
		//Asumiendo que no es un array
		String exp= expresion.generateCode();
		
		//TODO Ver d�nde queda el c�digo generado. Si al tope de la pila o en alg�n registro.
		codeGen.append(exp).append(System.getProperty("line.separator"));
		
		int posVariable = posVariable(variable);
		
		if(posArray==null) {
			//USO cx para asignaciones
			//Primera variable local: 12. posPrimera variable: 0.
			if(variable.isPorValor())
				codeGen.append("mov [bp-").append(posVariable).append("], ").append("cx").append(System.getProperty("line.separator"));
			else {
				codeGen.append("mov bx, ").append("[bp-").append(posVariable).append("], ").append(System.getProperty("line.separator"));
				codeGen.append("mov [bx], cx").append(System.getProperty("line.separator")).append(System.getProperty("line.separator"));
			}
		}
		else {
			
			codeGen.append(";------- Begin array assignment --------")
					.append( System.getProperty("line.separator") );
			
			// obtengo el codigo del indice. Es un valor o una variable
			String codigoIndice = "";
			
			try {
				// es un valor?
				NodeValor valor = (NodeValor)posArray;
				codigoIndice = valor.getValor().replace("n", "");
			}
			catch(Exception e) {
				// sino, es una variable
				NodeVariable var = (NodeVariable)posArray;
				codigoIndice = "[bp-" + var.getPos() + "]";
			}
			
			// multiplico el indice por 2 (porque es array de dword)
			codeGen.append("mov ax, " + codigoIndice).append( System.getProperty("line.separator") )
					.append("mov bx, 2").append( System.getProperty("line.separator") )
					.append("mul bx").append( System.getProperty("line.separator") );
			
			// muevo al registro "si" el indice del array
			codeGen.append("mov si, ax").append( System.getProperty("line.separator") );
			
			// asignar el valor al array
			codeGen.append( "mov global" + variable.getOrdenVariable() + "[si], cx" )
					.append( System.getProperty("line.separator") );
			/*
			NodeValor valor = null; 
			try {
				valor = (NodeValor)posArray;
			}
			catch(Exception e) {}
			
			if(valor != null) {
				codeGen.append("mov si, " + valor.getValor().replace("n", "") )
						.append( System.getProperty("line.separator") );
			}
			else {
				codeGen.append( expresion.generateCode() );
				
				codeGen.append("mov si, cx")
						.append( System.getProperty("line.separator") );
			}
	
			codeGen.append( "mov global" + variable.getOrdenVariable() + "[si], cx" )
					.append( System.getProperty("line.separator") );
			*/
			codeGen.append(";------- End array assignment --------")
					.append( System.getProperty("line.separator") )
					.append( System.getProperty("line.separator") );
			
		}
		
		return codeGen.toString();
	}

	public void setVariable(DeclaracionVariable variable) {
		this.variable = variable;
	}

	public DeclaracionVariable getVariable() {
		return variable;
	}
}
